﻿using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace XFGameFramework.SkillSystem
{

    public class SkillManager
    {
        #region Config

        private static Dictionary<string,SkillsConfig> configs = new Dictionary<string,SkillsConfig>();

        /// <summary>
        /// 添加技能配表
        /// </summary>
        /// <param name="skillsConfig">技能配置</param>
        /// <exception cref="Exception">ID重复</exception>
        public static void AddConfig(SkillsConfig skillsConfig)
        {
            if (skillsConfig == null) return;

            if (configs.ContainsKey(skillsConfig.name))
            {
                Debug.LogWarningFormat("已添加技能配置:{0},请勿重复添加!",skillsConfig.name);
                return;
            }

            foreach (var skill in skillsConfig.skills)
            {
                foreach (var config in configs.Values)
                {
                    if (config.GetSkillConfigData(skill.id) == null)
                        continue;

                    StringBuilder builder = new StringBuilder();
                    builder.Append("检测到技能id重复,");
                    builder.Append("配置:").Append(skillsConfig.name);
                    builder.Append("技能:").Append(skill.id).Append(skill.skill_name);
                    builder.Append("配置:").Append(config.name);
                    builder.Append("技能:").Append(skill.id).Append(config.GetSkillConfigData(skill.id).skill_name);

                    throw new Exception(builder.ToString());
                }
            }

            configs.Add(skillsConfig.name,skillsConfig);
        }

         
        /// <summary>
        /// 移除技能配表
        /// </summary>
        /// <param name="skillsConfig"></param>
        public static void RemoveConfig(SkillsConfig skillsConfig)
        {
            if (skillsConfig == null) return;

            if (configs.ContainsKey(skillsConfig.name)) 
                configs.Remove(skillsConfig.name); 
        }

        public static SkillsConfig GetConfig(string name) 
        {
            if (configs.ContainsKey(name))
                return configs[name];

            return null;
        }

        #endregion

        #region 字段

        private static List<IEquippableSkill> equipers = new List<IEquippableSkill>();

        private static List<int> skillsTemp = new List<int>();

        #endregion

        static SkillManager() 
        {
            UpdateManager.RemoveUpdateEvent(Update);
            UpdateManager.RemoveFixedUpdateEvent(FixedUpdate);
            UpdateManager.RemoveLateUpdateEvent(LateUpdate);

            UpdateManager.AddUpdateEvent(Update);
            UpdateManager.AddFixedUpdateEvent(FixedUpdate);
            UpdateManager.AddLateUpdateEvent(LateUpdate);
        }

        #region 方法

        private static SkillConfigData GetSkillInfo(int id)
        {
            foreach (var item in configs.Values)
            {
                SkillConfigData data = item.GetSkillConfigData(id);
                if (data == null) continue;
                return data;
            }

            return null;
        }


        /// <summary>
        /// 添加一组技能
        /// </summary>
        /// <param name="equipper">目标</param>
        /// <param name="skills">技能id集合</param>
        /// <exception cref="Exception"></exception>
        public static void AddSkills(IEquippableSkill equipper, IList<int> skills)
        {
            if (equipper.Skills == null)
                throw new Exception("请初始化IEquippableSkill.Skills!");
              
            foreach (var item in skills)
            {
                AddSkills(equipper, item);
            }
        }

        /// <summary>
        /// 添加一个技能
        /// </summary>
        /// <param name="equipper">目标</param>
        /// <param name="skillId">技能id</param>
        /// <exception cref="Exception"></exception>
        public static SkillBase AddSkills(IEquippableSkill equipper, int skillId)
        {
            if (equipper.Skills == null)
                throw new Exception("请初始化IEquippableSkill.Skills!");
            
            SkillBase skillBase = CreateSkill(equipper, skillId);

            if (!equipers.Contains(equipper))
                equipers.Add(equipper);

            return skillBase;
        }

        /// <summary>
        /// 移除某一个游戏角色身上的所有技能
        /// </summary>
        /// <param name="equipper">游戏物体</param>
        public static void RemoveSkills(IEquippableSkill equipper)
        {
            if (!equipers.Contains(equipper)) return;

            if (equipper == null || equipper.Skills == null || equipper.Skills.Count == 0)
            {
                equipers.Remove(equipper);
                return;
            }

            skillsTemp.Clear();
            foreach (var item in equipper.Skills.Values)
            {
                skillsTemp.Add(item.SkillData.id);
            }
            RemoveSkills(equipper, skillsTemp);
        }


        /// <summary>
        /// 移除某一个游戏角色身上的指定技能
        /// </summary>
        /// <param name="equipper">目标</param>
        /// <param name="skillId">技能id</param>
        public static void RemoveSkills(IEquippableSkill equipper, int skillId)
        {
            if (!equipper.Skills.ContainsKey(skillId))
                return;

            SkillBase skill = equipper.Skills[skillId];
            // 中断
            skill.Interrupt();
            // 移除
            skill.OnRemove();
            // 移除
            equipper.Skills.Remove(skillId);

            // 重置
            skill.ResetData();

            // 回收
            ClassObjectPoolManager.Unload(skill);

            if (equipper.Skills.Count != 0)
                return;

            if (!equipers.Contains(equipper))
                return;
            equipers.Remove(equipper);
        }

        /// <summary>
        /// 移除某一个游戏角色身上的一组技能
        /// </summary>
        /// <param name="equipper">目标</param>
        /// <param name="skills">技能id集合</param>
        public static void RemoveSkills(IEquippableSkill equipper, IList<int> skills)
        {
            foreach (var item in skills)
            {
                RemoveSkills(equipper, item);
            }
        }


        // 创建技能   

        private static SkillBase CreateSkill(IEquippableSkill equipper, int skillId)
        {
            if (equipper == null)
                throw new System.Exception("equiper is null!");

            if (equipper.Skills == null)
                throw new Exception("请初始化IEquippableSkill.Skills!");

            if (equipper.Skills.ContainsKey(skillId))
                throw new Exception(string.Format("技能已经创建:{0}", skillId));

            SkillConfigData skillData = GetSkillInfo(skillId);

            if (skillData == null)
                throw new Exception(string.Format("技能:{0}配置信息查询失败!", skillId));

            Type type = AssemblyTools.GetType(skillData.skill_class_full_name);

            if (type == null)
                throw new Exception(string.Format("未知的技能类型:{0} className:{1}", skillId, skillData.skill_class_full_name));

            SkillBase skill = ClassObjectPoolManager.Load(type) as SkillBase;

            if (skill == null)
                throw new Exception(string.Format("技能创建失败:{0} type:{1}", skillId, type.FullName));

            skill.SkillData = skillData;

            skill.Releaser = equipper;

            equipper.Skills.Add(skillId, skill);
            // 重置技能数据
            skill.ResetData();

            skill.OnAdd();

            return skill;
        }


        /// <summary>
        /// 中断所有技能
        /// </summary>
        /// <param name="equipper"></param>
        public static void InterruptAllSkill(IEquippableSkill equipper)
        {
            if (equipper == null) return;
            if (equipper is UnityEngine.Object) 
            {
                UnityEngine.Object obj = equipper as UnityEngine.Object;
                if (!obj) return;
            }
             
            foreach (var skill in equipper.Skills.Values)
            {
                skill.Interrupt();
            }
        }


        private static void Update()
        {
            for (int i = 0; i < equipers.Count; i++)
            {
                IEquippableSkill equippable = equipers[i];

                if (CheckDestroySkill(equippable))
                {
                    i--;
                    continue;
                }

                if (IsDisableSkill(equippable))
                    continue;

                foreach (var item in equippable.Skills.Values)
                {
                    item.Update();
                }
            }
        }

        private static void FixedUpdate()
        {

            for (int i = 0; i < equipers.Count; i++)
            {
                IEquippableSkill equippable = equipers[i];

                if (CheckDestroySkill(equippable))
                {
                    i--;
                    continue;
                }

                if (IsDisableSkill(equippable))
                    continue;

                foreach (var item in equippable.Skills.Values)
                {
                    if (item.IsReleasing)
                        item.FixedUpdate();
                }
            }

        }

        private static void LateUpdate()
        {
            for (int i = 0; i < equipers.Count; i++)
            {
                IEquippableSkill equippable = equipers[i];

                if (CheckDestroySkill(equippable))
                {
                    i--;
                    continue;
                }

                if (IsDisableSkill(equippable))
                    continue;

                foreach (var item in equippable.Skills.Values)
                {
                    if (item.IsReleasing)
                        item.OnLateUpdate();
                }
            }
        }


        /// <summary>
        /// 判断某个游戏角色是否正在释放技能
        /// </summary>
        /// <returns></returns>
        public static bool IsReleasingSkills(IEquippableSkill equipper)
        {
            if (equipper == null) return false;

            foreach (var item in equipper.Skills.Values)
            {
                if (item.IsReleasing)
                    return true;
            }
            return false;
        }



        private static bool CheckDestroySkill(IEquippableSkill equiper)
        {
            bool destroy = IsDestroySkill(equiper);

            if (destroy)
            {
                RemoveSkills(equiper);
                equipers.Remove(equiper);
            }

            return destroy;
        }


        /// <summary>
        /// 判断buff是否被销毁
        /// </summary>
        private static bool IsDestroySkill(IEquippableSkill equiper)
        {
            if (!(equiper is UnityEngine.Object)) return false;
            UnityEngine.Object obj = equiper as UnityEngine.Object;
            return !obj;
        }

        /// <summary>
        /// 判断buff是否被隐藏
        /// </summary>
        private static bool IsDisableSkill(IEquippableSkill equiper)
        {
            if (!(equiper is Component)) return false;
            Component obj = equiper as Component;
            return !obj.gameObject.activeInHierarchy;
        }


        #endregion
    }

}